#include "DocJsonAccess.h"
#include <iostream>
#include <fstream>
#include <streambuf>
#include "libjson.h"
#include "control/TermFactory.h"


namespace xpm {	
	
	void DocJsonAccess::Init() {
		// optionally you can implement your DOMLSSerializerFilter (e.g. MyDOMLSSerializerFilter)		
	}

	DocJsonAccess::~DocJsonAccess() {
		
	}

	int DocJsonAccess::Load(XpmTermDoc& doc) {
		ifstream infile;
		infile.open(m_filename.c_str());
		if(infile.is_open()) {
			string str((std::istreambuf_iterator<char>(infile)), istreambuf_iterator<char>());
			std::cout << "data:" << str << endl;
			std::size_t pos = str.find("\"_lang");
			if ( pos != string::npos ) {
				string signs = pos != string::npos ? "{" + str.substr(pos, str.size()-pos-1): "" ;
			    cout << "signs:" << signs << endl;
			    return Load(doc, signs);
			}
		}
		return false;
	}

	bool DocJsonAccess::Save(XpmTermDoc& doc, string& syntax) {
		return SaveAs(doc, m_filename.c_str(), syntax);
	}

	string DocJsonAccess::WriteTarget(XpmTermDoc& doc, string& syntax) {
		// get syntax node
		if ( syntax.size() > 0 ) {
			//json_push_back(syntaxn, json_new_a("test", "test"));
			// get signs node
			string output = syntax;
			if(doc.GetTermBlocks().size() > 0) {
				//json_string output_j = libjson::to_json_string(output);
				JSONNode n(JSON_NODE);
				//JSONNode blocks(JSON_ARRAY);	
				JSONNode lang(L"_lang", libjson::to_json_string(doc.lang()));
				n.push_back(lang);
				JSONNode blocks(JSON_ARRAY);
				blocks.set_name( L"signs blocks");
				for(std::list<XpmTermBlock*>::iterator it = doc.GetTermBlocks().begin(); it != doc.GetTermBlocks().end(); ++it) {
					if ( (*it)->GetTerms().size() > 0 ) {
						JSONNode block(JSON_NODE);
						block.push_back(JSONNode(L"bp", (*it)->position()));
						JSONNode terms(JSON_ARRAY);
						terms.set_name( L"signs");
						for(TermIter tit = (*it)->GetTerms().begin(); tit != (*it)->GetTerms().end(); ++tit) {
							std::cout << "write terms (1)" << endl;
							JSONNode term(JSON_NODE);	

							term.push_back(JSONNode(L"pos", tit->posInBlock()));
							term.push_back(JSONNode(L"signifier", libjson::to_json_string( tit->text())));
							term.push_back(JSONNode(L"signified", libjson::to_json_string( tit->iid())));
							terms.push_back(term);

							std::cout << "write terms (2)" << endl;
						}
						block.push_back(terms);
						blocks.push_back( block);
					}
				}
				n.push_back( blocks);
				json_string signsstr = n.write_formatted() ;
				output += "\n" + libjson::to_std_string( signsstr) ;
				//json_push_back(syntaxn, blocks);
			}
			//write file
			std::cout << output << endl;
			return output;
		}
	}

	bool DocJsonAccess::SaveAs(XpmTermDoc& doc, const char* filename, string& syntax) {
		// get syntax node
		if ( syntax.size() > 0 ) {
			//json_push_back(syntaxn, json_new_a("test", "test"));
			// get signs node
			string output = syntax;
			if(doc.GetTermBlocks().size() > 0) {
				output = output.substr(0, syntax.find_last_of("}"));
				//json_string output_j = libjson::to_json_string(output);
				JSONNode n(JSON_NODE);
				//JSONNode blocks(JSON_ARRAY);	
				JSONNode lang(L"_lang", libjson::to_json_string(doc.lang()));
				n.push_back(lang);
				JSONNode blocks(JSON_ARRAY);
				blocks.set_name( L"signs blocks");
				for(std::list<XpmTermBlock*>::iterator it = doc.GetTermBlocks().begin(); it != doc.GetTermBlocks().end(); ++it) {
					if ( (*it)->GetTerms().size() > 0 ) {
						JSONNode block(JSON_NODE);
						block.push_back(JSONNode(L"bp", (*it)->position()));
						JSONNode terms(JSON_ARRAY);
						terms.set_name( L"signs");
						for(TermIter tit = (*it)->GetTerms().begin(); tit != (*it)->GetTerms().end(); ++tit) {
							std::cout << "write terms (1)" << endl;
							JSONNode term(JSON_NODE);	

							term.push_back(JSONNode(L"pos", tit->posInBlock()));
							term.push_back(JSONNode(L"signifier", libjson::to_json_string( tit->text())));
							term.push_back(JSONNode(L"signified", libjson::to_json_string( tit->iid())));
							terms.push_back(term);

							std::cout << "write terms (2)" << endl;
						}
						block.push_back(terms);
						blocks.push_back( block);
					}
				}
				n.push_back( blocks);
				json_string signsstr = n.write_formatted() ;
				output += "," + libjson::to_std_string( signsstr) + "}";
				//json_push_back(syntaxn, blocks);
			}
			//write file
			std::cout << output << endl;
			ofstream outfile;
			//outfile.imbue(locale("chs"));
			outfile.open(DocAccess::GetFilename().c_str());
			if ( outfile.is_open()) {
				outfile << output.c_str();
				outfile.close();
				return true;
			}
		}
		return false;
		//JSONNode syntaxn = libjson::
	}

	bool DocJsonAccess::SaveAsPureJson(XpmTermDoc& doc, const char* filename, string& syntax) {
		// get syntax node
		JSONNode syntaxn = libjson::parse(libjson::to_json_string( syntax ));
		if ( !syntaxn.empty() ) {
			//json_push_back(syntaxn, json_new_a("test", "test"));
			// get signs node
			if(doc.GetTermBlocks().size() > 0) {
				//JSONNode blocks(JSON_ARRAY);	
				JSONNode blocks(JSON_ARRAY);
				blocks.set_name( L"signs blocks");
				for(std::list<XpmTermBlock*>::iterator it = doc.GetTermBlocks().begin(); it != doc.GetTermBlocks().end(); ++it) {
					std::cout << "write blocks" << endl;
					JSONNode block(JSON_NODE);
					block.push_back(JSONNode(L"bp", (*it)->position()));
					JSONNode terms(JSON_ARRAY);
					terms.set_name( L"signs");
					block.push_back( terms);
					for(TermIter tit = (*it)->GetTerms().begin(); tit != (*it)->GetTerms().end(); ++tit) {
						std::cout << "write terms (1)" << endl;
						JSONNode term(JSON_NODE);						
						term.push_back(JSONNode(L"pos", tit->posInBlock()));
						term.push_back(JSONNode(L"signifier", libjson::to_json_string( tit->text())));
						term.push_back(JSONNode(L"signified", tit->iid().c_str()));
						terms.push_back( term);
						std::cout << "write terms (2)" << endl;
					}
					blocks.push_back( block);
					std::cout << "write blocks (2)" << endl;
				}
				syntaxn.push_back( blocks);
				std::cout << "write blocks (3)" << endl;
			}
			//write file
			wstring output = syntaxn.write_formatted().c_str();
			std::wcout << output << endl;
			ofstream outfile;
			outfile.open(m_filename.c_str());
			if ( outfile.is_open()) {
				outfile << output.c_str();
				outfile.close();
				return true;
			}
		}
		return false;
		//JSONNode syntaxn = libjson::
	}

	int DocJsonAccess::Load(XpmTermDoc& doc, string str) {
		std::cout << "data:" << str << endl;
		JSONNode n = libjson::parse(libjson::to_json_string( str));
		if ( !n.empty() ) {
			JSONNode::json_iterator i =  n.begin();
			while ( i != n.end()) {
				wstring node_name = (*i).name().c_str();
				std::wcout << "node name:" << node_name << endl;
				if(json_strcmp((*i).name().c_str(), L"_lang")==0) {
						string lang = libjson::to_std_string((*i).as_string());
						doc.setLang(lang);
						DocAccess::_termControl = DocAccess::_termFactory->termControl(lang);
					}
				else if(json_strcmp((*i).name().c_str(), L"signs blocks")==0) {
					std::cout << "parse with json (1)" << endl;
					// parse signs blocks
					ParseSignsBlocks(*i, doc);
					std::cout << "parse with json (2)" << endl;
				}
				++i;

			}
			return true;
		}
		return true;
	}

	int DocJsonAccess::ParseWithJson(const char* filename, XpmTermDoc& doc) {
		ifstream infile;
		m_filename = filename;
		infile.open(m_filename.c_str());
		if(infile.is_open()) {
			string str((std::istreambuf_iterator<char>(infile)), istreambuf_iterator<char>());
			std::cout << "data:" << str << endl;
			std::size_t pos = str.find("\"_lang");
			if ( pos != string::npos ) {
				string signs = pos != string::npos ? "{" + str.substr(pos, str.size()-pos-1): "" ;
			    cout << "signs:" << signs << endl;
			    return Load(doc, signs);
			}
		}
		return false;
	}

	void DocJsonAccess::ParseSignsBlocks(JSONNode n, XpmTermDoc& doc) {
		JSONNode::json_iterator i = n.begin();
		std::cout << "parse with block (1)" << endl;
		while ( i != n.end()) {			
			XpmTermBlock* block = doc.CreateBlockAtEnd();
			JSONNode::json_iterator bi = (*i).begin();
			while ( bi != (*i).end()) {
				if(json_strcmp((*bi).name().c_str(), L"bp")== 0) {	
					int bp = (*bi).as_int();
					std::cout << "bp :" << bp << endl;
					block->setTextBlockPos(bp);
				}else if ( json_strcmp((*bi).name().c_str(), L"signs")==0 ) {
					ParseSigns(*bi, block);
				}
				++bi;
			}
			++i;
		}
		std::cout << "parse with block (2)" << endl;
	}
	
	void DocJsonAccess::ParseSigns(JSONNode n, XpmTermBlock* block) {
		JSONNode::json_iterator i =  n.begin();
		std::cout << "parse with signs (1)" << endl;
		while ( i != n.end()) {			
			JSONNode::json_iterator ti= (*i).begin();
			int pos = 0;
			string iid = "";
			wstring signifier = L"";
			while ( ti != (*i).end()) {
				wstring node_name = (*ti).name().c_str();
				if( node_name == L"pos") {				
					pos = (*ti).as_int();
				}else if ( node_name == L"signifier" ) {
					signifier = libjson::to_std_wstring ( (*ti).as_string());
					string signifier2 = libjson::to_std_string( (*ti).as_string() );
					cout << "signifier in string: " << signifier2 << endl;
					wcout << "signifier in wstring: " << signifier << endl;
				}else if ( node_name == L"signified" ) {
					iid = libjson::to_std_string( (*ti).as_string());
				}
				++ti;
			}
			if( DocAccess::_termControl  != 0 )
			    block->AppendTermRange(pos, signifier, DocAccess::_termControl->GetTermByIid(iid));
			++i;
		}
		std::cout << "parse with signs (2)" << endl;
	}
}